home *** CD-ROM | disk | FTP | other *** search
Text File | 1989-11-09 | 26.8 KB | 1,164 lines |
- Article 313 of comp.sources.unix:
- From: rsalz@uunet.uu.net (Rich Salz)
- Newsgroups: comp.sources.unix
- Subject: v18i054: Library for hat/coat and others
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Bob McQueer <mtxinu!rtech!weevil!bobm@uunet.uu.net>
- Posting-number: Volume 18, Issue 54
- Archive-name: mcqueer-lib
-
- [ I don't want to get into the practice of posting everyone's favorite
- toolkit/library... --r$ ]
-
- This is a small set of utilities for generic use, at least in bobm
- generated programs.
-
- ----------
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create:
- # README
- # Makefile
- # diagnostic.c
- # hash.c
- # prime.c
- # strstore.c
- # strtok.c
- export PATH; PATH=/bin:/usr/bin:$PATH
- echo shar: "extracting 'README'" '(637 characters)'
- if test -f 'README'
- then
- echo shar: "will not over-write existing file 'README'"
- else
- cat << \SHAR_EOF > 'README'
- This is a small set of utilities for generic use, at least in bobm
- generated programs:
-
- hash.c, prime.c - manage hash tables.
- strstore.c - store and free copies of strings.
- diagnostic.c - produce diagnostic & fatal error messages.
-
- read comments in the individual sources for directions on using them.
-
- strtok.c is also contained herein. If you are SYSV, or any other system
- which has that in the runtime library, remove it from the makefile.
-
- Before you build, fill in the makefile to put the results where you want them.
-
- hash.c and str_store.c manage dynamic memory. #define's in those files
- control allocation block sizes, etc.
- SHAR_EOF
- fi
- echo shar: "extracting 'Makefile'" '(810 characters)'
- if test -f 'Makefile'
- then
- echo shar: "will not over-write existing file 'Makefile'"
- else
- cat << \SHAR_EOF > 'Makefile'
- #
- # where to put the library
- #
- LIBARC = $(HOME)/lib/bobm.a
-
- # if your compiler doesn't like the initialization of a pointer with
- # an array address in strstore.c, define NO_PTR_INIT
- #
- # if you define HASHMAGIC to be some number, you will get magic number
- # checks in the hash table routines, which can be helpful in tracking
- # down instances of client code passing bad context addresses. Not done
- # by default to avoid overhead. See hash.c
- #
- CFLAGS = -O
-
- #
- # if strtok() is available in your c runtime library, remove it from
- # the list - this will be all SYSV, and some BSD systems like ULTRIX
- #
- LIBOBJS = hash.o diagnostic.o prime.o strstore.o strtok.o
-
- #
- # for SYSV, make RANLIB an effective no-op, like "ls" or "echo"
- #
- RANLIB = ranlib
-
- lib : $(LIBOBJS)
- ar rvu $(LIBARC) $(LIBOBJS)
- $(RANLIB) $(LIBARC)
- SHAR_EOF
- fi
- echo shar: "extracting 'diagnostic.c'" '(1977 characters)'
- if test -f 'diagnostic.c'
- then
- echo shar: "will not over-write existing file 'diagnostic.c'"
- else
- cat << \SHAR_EOF > 'diagnostic.c'
- #include <stdio.h>
-
- /*
- ** generic error message routines. Diag_xxx, may be externally set by caller.
- **
- ** possible portability problem - use of several "long" arguments to pass
- ** stack through to underlying printf() family routine.
- */
-
- /*
- **
- ** Copyright (c) 1987, Robert L. McQueer
- ** All Rights Reserved
- **
- ** Permission granted for use, modification and redistribution of this
- ** software provided that no use is made for commercial gain without the
- ** written consent of the author, that all copyright notices remain intact,
- ** and that all changes are clearly documented. No warranty of any kind
- ** concerning any use which may be made of this software is offered or implied.
- **
- */
-
- char *Diag_file = ""; /* filename for use in diagnostic message */
- int Diag_line = 1; /* diagnostic line number */
- int Diag_count = 0; /* diagnostic counter */
- FILE *Diag_fp = stderr; /* output stream for messages */
- char *Diag_cmd = "?"; /* command name for fatal() / usage() */
-
- static int (*Fatcall)() = NULL;
-
- /*
- ** print nonfatal diagnostic with line number from an input file. Format
- ** compatible with "context"
- */
- diagnostic(s,a,b,c,d,e,f)
- char *s;
- long a,b,c,d,e,f;
- {
- fprintf(Diag_fp,"%s line %d: ",Diag_file,Diag_line);
- fprintf(Diag_fp,s,a,b,c,d,e,f);
- fprintf(Diag_fp,"\n");
- ++Diag_count;
- }
-
- /*
- ** print fatal error message and exit. May call user set cleanup routine first.
- ** argument list passed to fatal() will also be passed to cleanup routine.
- */
- fatal (s,a,b,c,d,e,f)
- char *s;
- long a,b,c,d,e,f;
- {
- fprintf (Diag_fp,"%s: ",Diag_cmd);
- fprintf (Diag_fp,s,a,b,c,d,e,f);
- fprintf (Diag_fp,"\n");
- if (Fatcall != NULL)
- (*Fatcall) (s,a,b,c,d,e,f);
- exit (1);
- }
-
- /*
- ** set cleanup routine for fatal() calls
- */
- fat_set (fn)
- int (*fn) ();
- {
- Fatcall = fn;
- }
-
- /*
- ** print usage message and exit.
- */
- usage (s,a,b,c,d,e,f)
- char *s;
- long a,b,c,d,e,f;
- {
- fprintf (Diag_fp,"usage: %s ",Diag_cmd);
- fprintf (Diag_fp,s,a,b,c,d,e,f);
- fprintf (Diag_fp,"\n");
- exit (1);
- }
- SHAR_EOF
- fi
- echo shar: "extracting 'hash.c'" '(11529 characters)'
- if test -f 'hash.c'
- then
- echo shar: "will not over-write existing file 'hash.c'"
- else
- cat << \SHAR_EOF > 'hash.c'
- #include <stdio.h>
-
- /*
- **
- ** Copyright (c) 1987, Robert L. McQueer
- ** All Rights Reserved
- **
- ** Permission granted for use, modification and redistribution of this
- ** software provided that no use is made for commercial gain without the
- ** written consent of the author, that all copyright notices remain intact,
- ** and that all changes are clearly documented. No warranty of any kind
- ** concerning any use which may be made of this software is offered or implied.
- **
- */
-
- /*
- ** generic hash table routines.
- **
- ** htab_init - initialize a new hash table
- ** htab_free - destroy a hash table, freeing associated memory
- ** htab_clear - remove all hash table entries
- ** htab_find - find entry
- ** htab_del - delete entry
- ** htab_enter - enter item into table
- ** htab_list - scan hash table entries.
- **
- ** Multiple hash tables may be used. Caller may provide key comparison
- ** and hash routines, or use defaults.
- */
-
- /*
- ** HASHMAGIC define may be used to compile a version of these routines
- ** which will catch bad context blocks passed in by client routines
- ** through a magic number check. If defined, HASHMAGIC should be the
- ** actual number to use for a magic number. Configurable so that you
- ** may avoid the overhead of checking it all the time in these routines
- ** which may have high entry rates.
- */
-
- /*
- ** allocation: nodes are allocated starting with a block of ALLOCINIT,
- ** doubling the size for the next allocation as long as the size is strictly
- ** less than ALLOCLIMIT. If you make ALLOCLIMIT a value encountered by
- ** successive doubling of ALLOCINIT, that will be the final size, otherwise the
- ** next doubling larger.
- **
- ** The idea of this stunt is that we don't know whether the caller is going
- ** to make a lot of entries, or just a few. So we start out allocating
- ** just a few nodes at a crack, and as the caller makes more and more
- ** entries, allocate bigger bunches. For memory-restrictive environments
- ** like MS-DOS, one could set ALLOCLIMIT low & simply pay the penalty for
- ** lots of malloc calls.
- */
- #define ALLOCINIT 25
- #define ALLOCLIMIT 800
-
- #define MAGCHECK(T,N) if (T->magic != HASHMAGIC) fatal(Merr,N)
-
- typedef struct _htab
- {
- struct _htab *next;
- char *key;
- char *data;
- } HASHTAB;
-
- typedef struct _faddr
- {
- struct _faddr *next;
- } FADDR;
-
- /*
- ** fpool, tpool - tpool is the pool of available nodes. Every time
- ** a new block is allocated, one FADDR is allocated along with it.
- ** The address allocated is coerced into the FADDR and placed on fpool
- ** to facilitate freeing.
- */
-
- typedef struct
- {
- #ifdef HASHMAGIC
- int magic;
- #endif
- HASHTAB **tab; /* hash table */
- HASHTAB *tpool; /* available nodes */
- HASHTAB *srch; /* current search pointer for htab_list */
- FADDR *fpool; /* alloc pointers for htab_free */
- int (*afail)(); /* allocation error handler */
- int (*compare)(); /* comparison routine */
- int (*hashfunc)(); /* hash function */
- int size; /* size of table (length of tab item) */
- int ablock; /* current allocation block size */
- int srchidx; /* current table index for htab_list */
- } CONTEXT;
-
- extern char *malloc();
-
- #ifdef HASHMAGIC
- static char *Merr = "Bad magic number in hash table context block, %s()";
- #endif
-
- /*
- ** free hash table. tab is pointer returned by htab_init.
- */
- htab_free(tab)
- char *tab;
- {
- register FADDR *ptr, *next;
- int i;
- register CONTEXT *cb;
-
- cb = (CONTEXT *) tab;
-
- #ifdef HASHMAGIC
- MAGCHECK(cb,"htab_free");
- ++(cb->magic);
- #endif
-
- for (ptr = cb->fpool; ptr != NULL; ptr = next)
- {
- next = ptr->next;
- free ((char *) ptr);
- }
-
- free (tab);
- }
-
- /*
- ** remove all hash table entries. Does not free memory, simply restores
- ** empty table, as if one had called htab_delete on all the keys. tab is
- ** pointer returned by htab_init.
- */
- htab_clear(tab)
- char *tab;
- {
- register CONTEXT *cb;
- register HASHTAB **tptr;
- register HASHTAB *nptr;
- int i;
-
- cb = (CONTEXT *) tab;
-
- #ifdef HASHMAGIC
- MAGCHECK(cb,"htab_clear");
- #endif
-
- tptr = cb->tab;
-
- for (i=0; i < cb->size; ++i,++tptr)
- {
- nptr = *tptr;
- if (nptr == NULL)
- continue;
- while (nptr->next != NULL)
- nptr = nptr->next;
- nptr->next = cb->tpool;
- cb->tpool = *tptr;
- *tptr = NULL;
- }
-
- /* force any open htab_list's to return empty */
- cb->srch = NULL;
- cb->srchidx = cb->size;
- }
-
- /*
- ** initialize a hash table. Returns a pointer to be used with other
- ** calls, NULL for failure.
- **
- ** The hash table will be maintained as a linked list for each node,
- ** so any number of entries can be made to it, whatever the value for
- ** size (>100% density is perfectly OK).
- **
- ** size - size of table. If hfunc is NULL, will be incremented
- ** up to a prime size to suit the type of hash function
- ** used by default. Caller may find out the actual size
- ** by calling next_prime().
- **
- ** allocfail - routine to call in case of memory allocation failure.
- ** If NULL, allocation failure will make a call to fatal().
- **
- ** comp - routine used to compare keys. returns 0 if equal, non-zero
- ** otherwise. If NULL, strcmp() will be used. Your own will
- ** have to be provided if your keys are something other than
- ** strings. These routines will always call this with the
- ** comparison key as the first argument, and the one in the
- ** table already as a second argument. This fact is most
- ** useful for making comparisons up to the length of the entered
- ** key, for instance.
- **
- ** hfunc - hash function. called as (*hfunc)(key, size). size argument
- ** may be ignored if function was written for a specific size.
- ** Must return an integer between 0 and size-1. If NULL, the
- ** default hash function is the typical "string-divided-modulo
- ** -table-size" algorithm.
- */
- char *
- htab_init(size,allocfail,comp,hfunc)
- int size;
- int (*allocfail)();
- int (*comp)();
- int (*hfunc)();
- {
- int def_afail();
- int strcmp();
- int hash();
- int i;
- CONTEXT *cb;
-
- if (allocfail == NULL)
- allocfail = def_afail;
-
- if (comp == NULL)
- comp = strcmp;
-
- if (hfunc == NULL)
- {
- size = next_prime(size);
- hfunc = hash;
- }
-
- i = sizeof(CONTEXT) + size * sizeof(HASHTAB *);
-
- if ((cb = (CONTEXT *) malloc(i)) == NULL)
- {
- (*allocfail)();
- return (NULL);
- }
-
- #ifdef HASHMAGIC
- cb->magic = HASHMAGIC;
- #endif
-
- cb->afail = allocfail;
- cb->compare = comp;
- cb->hashfunc = hfunc;
- cb->size = size;
- cb->tab = (HASHTAB **)(cb+1);
-
- for (i=0; i < cb->size; ++i)
- (cb->tab)[i] = NULL;
- cb->tpool = NULL;
- cb->fpool = NULL;
- cb->ablock = ALLOCINIT;
-
- /* safety, in case somebody calls htab_list wrong */
- cb->srch = NULL;
- cb->srchidx = size;
-
- return ((char *) cb);
- }
-
-
- /*
- ** find an entry in hash table. The pointer returned is NULL for
- ** failure, or the data pointer associated with the key in htab_enter.
- **
- ** tab - table pointer returned by htab_init.
- ** s - search key.
- */
- char *
- htab_find(tab,s)
- char *tab;
- char *s;
- {
- register HASHTAB *ptr;
- register CONTEXT *cb;
-
- cb = (CONTEXT *) tab;
-
- #ifdef HASHMAGIC
- MAGCHECK(cb,"htab_find");
- #endif
-
- for (ptr = (cb->tab)[(*(cb->hashfunc))(s,cb->size)];
- ptr != NULL; ptr = ptr->next)
- {
- if ((*(cb->compare))(s,ptr->key) == 0)
- return (ptr->data);
- }
-
- return (NULL);
- }
-
- /*
- ** delete a hash table entry. Returns 0 for success, <0 for no entry.
- **
- ** tab - table pointer returned by htab_init.
- ** s - search key.
- */
- htab_del(tab,s)
- char *tab;
- char *s;
- {
- register HASHTAB *ptr;
- register CONTEXT *cb;
- register HASHTAB *pred;
- int idx;
-
- cb = (CONTEXT *) tab;
-
- #ifdef HASHMAGIC
- MAGCHECK(cb,"htab_del");
- #endif
-
- pred = NULL;
- for (ptr = (cb->tab)[idx = (*(cb->hashfunc))(s,cb->size)];
- ptr != NULL; ptr = ptr->next)
- {
- if ((*(cb->compare))(s,ptr->key) == 0)
- break;
- pred = ptr;
- }
-
- if (ptr == NULL)
- return (-1);
-
- /*
- ** if we're deleting the current search index in the middle
- ** of an htab_list, go to next item.
- */
- if (ptr == cb->srch)
- cb->srch = ptr->next;
-
- if (pred == NULL)
- (cb->tab)[idx] = ptr->next;
- else
- pred->next = ptr->next;
- ptr->next = cb->tpool;
- cb->tpool = ptr;
-
- return (0);
- }
-
- /*
- ** enter new item into hash table:
- **
- ** tab - table pointer from htab_init.
- ** s - key.
- ** data - data to associate with key. In most cases, will probably
- ** actually be a pointer to some sort of structure known
- ** to the caller.
- **
- ** both s and data should point to storage valid for the entire life of
- ** the table. htab_enter can not allocate copies of either of these
- ** things since it does not know their structure (if you provided
- ** comparison & hash routines, the key may not actually be a string).
- ** htab_enter WILL allocate actual table nodes. Returns 0 for success,
- ** -1 for failure. Failure return is possible only if allocation
- ** failure occurs, and was not set up as fatal in htab_init().
- */
- htab_enter(tab,s,data)
- char *tab;
- char *s;
- char *data;
- {
- register HASHTAB *ptr;
- register CONTEXT *cb;
- HASHTAB *get_node();
- int i;
-
- cb = (CONTEXT *) tab;
-
- #ifdef HASHMAGIC
- MAGCHECK(cb,"htab_enter");
- #endif
-
- if ((ptr = get_node(cb)) == NULL)
- return (-1);
-
- ptr->next = (cb->tab)[i = (*(cb->hashfunc))(s,cb->size)];
- (cb->tab)[i] = ptr;
- ptr->key = s;
- ptr->data = data;
- return (0);
- }
-
- /*
- ** Routine to scan all hash table entries through successive calls.
- ** Returns 1 if an entry found, 0 for no more entries. Will not
- ** be returned in any particular order comprehensible to the
- ** calling program (hash table order).
- **
- ** tab - table pointer from htab_init
- ** first - 1 to start scan, 0 on succesive calls.
- ** data, key - returned data and key.
- **
- ** Precautions have been taken to allow interleave of this routine with
- ** htab_del and htab_clear, but the only interleave that truly makes
- ** sense is to selectively htab_del() entries on some basis as they
- ** come back from htab_list(). htab_enter()'s in mid list scan may be
- ** done, but they may or may not show up on following calls, dependent
- ** on where they were entered in relation to the current list pointer.
- **
- ** This routine sets a global variable on all successful calls:
- **
- ** int Htab_Index; hash table index entry was found at.
- **
- ** By examining this while scanning the list of entries, a caller may
- ** obtain statistics on table distribution. The value will increase
- ** monotonically as the search proceeds, skipping across indices
- ** with no entries.
- */
-
- int Htab_Index;
-
- htab_list(tab,first,data,key)
- char *tab;
- int first;
- char **data;
- char **key;
- {
- register CONTEXT *cb;
-
- cb = (CONTEXT *) tab;
-
- #ifdef HASHMAGIC
- MAGCHECK(cb,"htab_list");
- #endif
-
- if (first)
- {
- cb->srch = NULL;
- cb->srchidx = -1;
- }
-
- while (cb->srch == NULL)
- {
- ++(cb->srchidx);
- if (cb->srchidx >= cb->size)
- return (0);
- cb->srch = (cb->tab)[cb->srchidx];
- }
-
- Htab_Index = cb->srchidx;
-
- *data = (cb->srch)->data;
- *key = (cb->srch)->key;
-
- cb->srch = (cb->srch)->next;
- return(1);
- }
-
- static HASHTAB *
- get_node(cb)
- CONTEXT *cb;
- {
- char *addr;
- HASHTAB *ptr;
- int i;
-
- if (cb->tpool == NULL)
- {
- addr = malloc((cb->ablock)*sizeof(HASHTAB)+sizeof(FADDR));
- if (addr == NULL)
- {
- (*(cb->afail))();
- return (NULL);
- }
-
- ((FADDR *) addr)->next = cb->fpool;
- cb->fpool = (FADDR *) addr;
- addr += sizeof(FADDR);
- cb->tpool = (HASHTAB *) addr;
- for (i=1; i < cb->ablock; ++i)
- (cb->tpool)[i-1].next = cb->tpool + i;
- (cb->tpool)[i-1].next = NULL;
-
- if (cb->ablock < ALLOCLIMIT)
- cb->ablock *= 2;
- }
-
- ptr = cb->tpool;
- cb->tpool = (cb->tpool)->next;
- return (ptr);
- }
-
- static int
- hash(s,size)
- register char *s;
- int size;
- {
- register long rem;
-
- for (rem = 0; *s != '\0'; ++s)
- rem = (rem * 128 + *s) % size;
- return(rem);
- }
-
- static int
- def_afail()
- {
- fatal("memory allocation failure in hash table routines");
- }
- SHAR_EOF
- fi
- echo shar: "extracting 'prime.c'" '(1566 characters)'
- if test -f 'prime.c'
- then
- echo shar: "will not over-write existing file 'prime.c'"
- else
- cat << \SHAR_EOF > 'prime.c'
- /*
- **
- ** Copyright (c) 1987, Robert L. McQueer
- ** All Rights Reserved
- **
- ** Permission granted for use, modification and redistribution of this
- ** software provided that no use is made for commercial gain without the
- ** written consent of the author, that all copyright notices remain intact,
- ** and that all changes are clearly documented. No warranty of any kind
- ** concerning any use which may be made of this software is offered or implied.
- **
- */
-
- /* return smallest prime >= i */
- int
- next_prime(i)
- int i;
- {
- if (i <= 2)
- return (2);
- if ((i%2) == 0)
- ++i;
- while (! is_prime(i))
- i += 2;
- return (i);
- }
-
- /*
- ** simply check all factors <= the square root of the number, with
- ** a minor wrinkle:
- **
- ** we split our checks into two separate chains which cover all
- ** numbers with no factors of 2 or 3, avoiding many of the non-
- ** prime factors. factor1 winds up being all integers = 5 mod 6,
- ** factor2 all integers >= 7 which = 1 mod 6. Anything = 0,2,3 or
- ** 4 mod 6 divides by 2 or 3.
- **
- ** this gives a rather small number of redundant factor checks for
- ** reasonable sized arguments (say < 10000). Only for extremely large
- ** numbers would the extra overhead justify a "smarter" algorithm.
- **
- ** only valid for i >= 2.
- */
- int
- is_prime(i)
- int i;
- {
- int factor1,factor2;
-
- if (i == 2 || i == 3)
- return(1);
-
- if ((i%3) == 0 || (i%2) == 0)
- return(0);
-
- factor1 = 5;
- factor2 = 7;
- while ((factor1 * factor1) <= i)
- {
- if ((i % factor1) == 0)
- return (0);
- if ((i % factor2) == 0)
- return (0);
- factor1 += 6;
- factor2 += 6;
- }
-
- return (1);
- }
- SHAR_EOF
- fi
- echo shar: "extracting 'strstore.c'" '(7804 characters)'
- if test -f 'strstore.c'
- then
- echo shar: "will not over-write existing file 'strstore.c'"
- else
- cat << \SHAR_EOF > 'strstore.c'
- #include <stdio.h>
-
- /*
- **
- ** Copyright (c) 1987, Robert L. McQueer
- ** All Rights Reserved
- **
- ** Permission granted for use, modification and redistribution of this
- ** software provided that no use is made for commercial gain without the
- ** written consent of the author, that all copyright notices remain intact,
- ** and that all changes are clearly documented. No warranty of any kind
- ** concerning any use which may be made of this software is offered or implied.
- **
- */
-
- /*
- ** string storage routines.
- **
- ** str_store - return an allocated copy of a string
- ** str_free - free all the strings
- ** str_cnew - make a new context block for separate group of strings
- ** str_ccur - return the current context block
- ** str_cset - set the context block
- ** str_cfree - free a context block
- ** str_afail - set allocation failure routine
- **
- ** Callers who simply need to make a single group of "permanent" strings
- ** for the life of their process need only call str_store, without worrying
- ** about context pointers. This will probably be suitable for a lot of
- ** applications. The other routines may be used to create separate groups
- ** of strings which may be released individually. The burden on callers
- ** to keep track of current context in these cases is traded off against
- ** the simplicity for the other case.
- **
- ** The intent of these routines is to "micro-allocate" strings into a
- ** large block of storage, saving malloc() headers. If used exclusively
- ** to store long strings, it might be inefficient.
- */
-
- char *malloc();
-
- /* actual malloc'ed block will be CH_BLOCK + sizeof(CHAIN) */
- #define CH_BLOCK (4096 - sizeof(CHAIN))
-
- #define MAGICNUM 0x525
-
- typedef struct _chain
- {
- struct _chain *next;
- int avail;
- char *store;
- } CHAIN;
-
- typedef struct
- {
- int magic;
- CHAIN *flist;
- } CONTEXT;
-
- static CONTEXT Cb_def[1] =
- {
- { MAGICNUM, NULL }
- };
-
- /*
- ** NO_PTR_INIT may be defined if the compiler barfs on attempts
- ** to initialize a pointer with an array name. If defined, extra
- ** checks will be made at routine entry to do the initialization
- ** first time through
- */
- #ifdef NO_PTR_INIT
- static CONTEXT *Cb = NULL;
- #else
- static CONTEXT *Cb = Cb_def;
- #endif
-
- static def_afail()
- {
- fatal ("memory allocation failure in string storage");
- }
-
- static int (*Afail)() = def_afail;
-
- /*
- ** str_store: return an allocated copy of a string.
- **
- ** s - the string to make a copy of. If NULL, an empty string
- ** will be returned.
- **
- ** NOTE: these strings may not be individually freed. This routine
- ** is intended to save memory used for alloc headers by returning
- ** pointers into a large blocks of allocated memory.
- **
- ** Will return NULL for allocation failure if a non-fatal failure
- ** routine has been defined (see str_afail). The default failure
- ** routine calls "fatal" with an error message. If the failure
- ** routine does not return, a NULL return from this routine is
- ** impossible.
- */
-
- char *
- str_store(s)
- char *s;
- {
- int len, av, idx;
- char *rptr;
- CHAIN *fp;
-
- #ifdef NO_PTR_INIT
- if (Cb == NULL)
- Cb = Cb_def;
- #endif
-
- if (s == NULL)
- s = "";
-
- len = strlen(s) + 1;
-
- /* should return inside loop */
- for (idx = 0; idx < 2; ++idx)
- {
- for (fp = Cb->flist; fp != NULL; fp = fp->next)
- {
- if (fp->avail >= len)
- {
- strcpy ((rptr = fp->store),s);
- fp->store += len;
- fp->avail -= len;
- return (rptr);
- }
- }
-
- /* alloc new block, let it find it on next iteration */
- if (len > CH_BLOCK)
- av = len;
- else
- av = CH_BLOCK;
- if ((rptr = malloc(av + sizeof(CHAIN))) == NULL)
- {
- (*Afail)();
- return (NULL);
- }
- fp = (CHAIN *) rptr;
- fp->next = Cb->flist;
- Cb->flist = (CHAIN *) fp;
- fp->store = rptr + sizeof(CHAIN);
- fp->avail = av;
- }
-
- /* we're screwed up */
- fatal("str_store: BAD craziness");
- return(NULL);
- }
-
- /*
- ** str_free:
- **
- ** Free all the strings allocated with str_store. All of those
- ** pointers will no longer be valid.
- **
- ** If str_cnew / str_cset have been used, this call frees the strings
- ** in the current context block.
- **
- ** str_store calls may still be made after this - you're simply
- ** starting over.
- */
- str_free()
- {
- CHAIN *ptr;
-
- #ifdef NO_PTR_INIT
- if (Cb == NULL)
- Cb = Cb_def;
- #endif
-
- for ( ; Cb->flist != NULL; Cb->flist = ptr)
- {
- ptr = (Cb->flist)->next;
- free ((char *) Cb->flist);
- }
- }
-
- /*
- ** str_cnew:
- **
- ** Make a new context block for str_store()
- **
- ** A pointer returned from this routine or str_ccur() is the ONLY
- ** valid argument for str_cset.
- **
- ** In effect what you are doing is declaring a new "pool" for all
- ** str_store() calls, probably so you can use str_free() to release
- ** groups of strings selectively.
- **
- ** NOTE: you MUST call str_cset() to actually use this new pool.
- **
- ** You MUST save this pointer to be able to add more strings to
- ** or free the pool. Any number of str_cnew calls may be made,
- ** allowing the caller to have as many "pools" of strings as
- ** desired. It is up to the caller to keep track of the context
- ** pointers, and which context block is currently in use.
- **
- ** NULL will be returned for failure to allocate a new context block.
- ** This return is only possible if a non-fatal allocation failure
- ** routine has been defined.
- */
- char *
- str_cnew()
- {
- CONTEXT *ctx;
-
- /*
- ** this is an inefficient use of malloc, but presumably callers
- ** aren't going to define large numbers of context blocks
- */
- if ((ctx = (CONTEXT *) malloc(sizeof(CONTEXT))) == NULL)
- {
- (*Afail)();
- return (NULL);
- }
-
- ctx->magic = MAGICNUM;
- ctx->flist = NULL;
- return ((char *) ctx);
- }
-
- /*
- ** str_ccur:
- **
- ** return pointer to context in current use, presumably so
- ** you can use str_cset to switch back to it later.
- */
- char *
- str_ccur()
- {
- #ifdef NO_PTR_INIT
- if (Cb == NULL)
- Cb = Cb_def;
- #endif
- return ((char *) Cb);
- }
-
- /*
- ** str_cset:
- **
- ** Set str_store() to a new context block. The ONLY
- ** legitimate argument for this routine is an address returned
- ** from a previous str_cnew() or str_ccur().
- **
- ** All old strings are still valid. Only str_free returns any
- ** storage.
- **
- ** You may recover the default context prior to any str_cset calls
- ** by setting NULL
- */
- str_cset(ptr)
- char *ptr;
- {
- if (ptr == NULL)
- Cb = Cb_def;
- else
- Cb = (CONTEXT *) ptr;
- if (Cb->magic != MAGICNUM)
- fatal("bad context pointer in str_cset");
- }
-
- /*
- ** the ONLY legal argument to this routine is pointer returned from
- ** str_cnew. This routine may be used to indicate that no more strings
- ** are to be allocated on that context block, and the pointer will no
- ** longer be a legal argument to str_cset. Note that the actual
- ** strings are still allocated, giving you a way to close a pool
- ** while retaining the strings. If you want to free BOTH the actual
- ** string storage and the pool, you must use str_free first, then
- ** switch context, so that this block is not the current context.
- **
- ** -1 returned for errors - attempts to free the current block or
- ** the default block.
- **
- ** Although the current implementation makes ptr a legal address for
- ** free(), callers should come through this routine instead, to
- ** allow that to change.
- */
- str_cfree(ptr)
- char *ptr;
- {
- if (ptr == (char *) Cb_def || ptr == (char *) Cb)
- return (-1);
-
- if (((CONTEXT *) ptr)->magic != MAGICNUM)
- fatal("bad context pointer in str_cfree");
-
- /* make it illegal to use freed context block */
- ((CONTEXT *) ptr)->magic = MAGICNUM + 1;
-
- free(ptr);
- return(0);
- }
-
- /*
- ** str_afail:
- **
- ** define the routine to be called in the event of an allocation
- ** failure. By default, fatal() will be called with an error message.
- ** You may reset the default by using NULL.
- **
- ** Returns old failure function to allow resetting.
- */
-
- typedef int (*FPTR)(); /* needed typedef for Sun compiler */
-
- FPTR str_afail(func)
- int (*func)();
- {
- int (*old)();
-
- old = Afail;
- if (func == NULL)
- Afail = def_afail;
- Afail = func;
- return (old);
- }
- SHAR_EOF
- fi
- echo shar: "extracting 'strtok.c'" '(894 characters)'
- if test -f 'strtok.c'
- then
- echo shar: "will not over-write existing file 'strtok.c'"
- else
- cat << \SHAR_EOF > 'strtok.c'
- #include <stdio.h>
-
- /*
- ** strtok() is a routine present in SYSV and some BSD runtime libraries.
- ** Use this if it isn't in yours.
- */
-
- static char *Save=NULL;
-
- char *index ();
- static char *first_ch (), *last_ch();
-
- char *
- strtok(str,delim)
- char *str, *delim;
- {
- register char *tokstart, *tokend;
-
- if (str != NULL)
- Save = str;
-
- if (Save == NULL)
- return (NULL);
-
- tokstart = first_ch (Save, delim);
- tokend = last_ch (tokstart, delim);
- Save = first_ch (tokend, delim);
- *tokend = '\0';
-
- if (*tokstart == '\0')
- return (NULL);
-
- return (tokstart);
- }
-
- static char *
- first_ch (str,delim)
- char *str;
- register char *delim;
- {
- register char *f;
-
- for (f = str; *f != '\0' && index(delim,*f) != NULL; ++f)
- ;
-
- return (f);
- }
-
- static char *
- last_ch (str,delim)
- char *str;
- register char *delim;
- {
- register char *f;
-
- for (f = str; *f != '\0' && index(delim,*f) == NULL; ++f)
- ;
-
- return (f);
- }
- SHAR_EOF
- fi
- exit 0
- # End of shell archive
-
- --
- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
-
-
-